package cn.supermay.tool.code;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class CodeGen {
	
	private String absolutePath;
	private Map<String, String> metas;

	public void setRootDir(String absolutePath) {
		this.absolutePath = absolutePath;
	}
	
	public void setNamings(
			final String entity,
			final String table,
			final String repository,
			final String service,
			final String serviceImpl,
			final String controller,
			final String controllerUri,
			String bean) {
		
		metas = new HashMap<String, String>();
		
		metas.put("ENTITY", entity);
		metas.put("TABLE", table);
		metas.put("REPOSITORY", repository);
		metas.put("SERVICE", service);
		metas.put("SERVICEIMPL", serviceImpl);
		metas.put("CONTROLLER", controller);
		metas.put("CONTROLLER_URI", controllerUri);
		metas.put("BEAN", bean);

	}

	public void genEntityFile(final String packageName) throws IOException {
		metas.put("ENTITY_CLASS", packageName+'.'+metas.get("ENTITY"));
		metas.put("PACKAGENAME", packageName);
		
		__gen_by_template__("Entity", metas.get("ENTITY"));
	}
	
	public void genRepositoryFile(final String packageName) throws IOException {
		metas.put("REPOSITORY_CLASS", packageName+'.'+metas.get("REPOSITORY"));
		metas.put("PACKAGENAME", packageName);
		
		__gen_by_template__("Repository", metas.get("REPOSITORY"));
	}

	public void genServiceFile(final String packageName) throws IOException {
		metas.put("SERVICE_CLASS", packageName+'.'+metas.get("SERVICE"));
		metas.put("PACKAGENAME", packageName);
		
		__gen_by_template__("Service", metas.get("SERVICE"));
	}
	
	public void genServiceImplFile(final String packageName) throws IOException {
		metas.put("SERVICEIMPL_CLASS", packageName+'.'+metas.get("SERVICEIMPL"));
		metas.put("PACKAGENAME", packageName+".impl");
		
		__gen_by_template__("ServiceImpl", metas.get("SERVICEIMPL"));
	}

	public void genControllerFile(final String packageName) throws IOException {
		metas.put("PACKAGENAME", packageName);
		
		__gen_by_template__("Controller", metas.get("CONTROLLER"));
	}

	public void genBeanFile(final String packageName) throws IOException {
		metas.put("BEAN_CLASS", packageName+'.'+metas.get("BEAN"));
		metas.put("PACKAGENAME", packageName);
		
		__gen_by_template__("Bean", metas.get("BEAN"));
	}
	
	private void __gen_by_template__(final String templateFile, final String className) throws IOException {
		
		File rootDir = Paths.get(absolutePath).toFile();
		if (!rootDir.exists()) {
			throw new IOException("Path does not exist: " + absolutePath);
		}
		if (!rootDir.isDirectory()) {
			throw new IOException("Path is not a directory: " + absolutePath);
		}


		String [] midPaths = metas.get("PACKAGENAME").split("\\.");
		
		StringBuffer destPath = new StringBuffer(absolutePath);
		for (String mp : midPaths) {
			destPath.append(System.getProperty("file.separator"));
			destPath.append(mp);
			
			if (! Files.exists(Paths.get(destPath.toString()))) {
				Files.createDirectory(Paths.get(destPath.toString()));
			}
		}
		destPath.append(System.getProperty("file.separator"));
		destPath.append(className).append('.').append("java");
		
		File javaFile = new File(destPath.toString()); 
				// Files.createFile(Paths.get(destPath.toString())).toFile();
		
		String templateContent = __read_from_template__(templateFile+".tpl");
		
		Set<Entry<String, String>> metaEnts = metas.entrySet();
		for (Entry<String, String> e : metaEnts) {
			templateContent = templateContent.replaceAll("\\$"+e.getKey()+"\\$", e.getValue());
		}

		// output to file
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(javaFile));
		bos.write(templateContent.getBytes());
		bos.close();
	}
	
	private String __read_from_template__(final String templateFileName) throws IOException {
		InputStream is = CodeGen.class.getClassLoader().getResourceAsStream(templateFileName);
		BufferedInputStream bis = new BufferedInputStream(is);

		StringBuffer sb = new StringBuffer();
		byte[] bytes = new byte[1024*8];
		while (bis.available()>0) {
			int size = bis.read(bytes);
			sb.append(new String(bytes, 0, size));
		}
		is.close();
		
		return sb.toString();
	}
}
